<!DOCTYPE HTML>
<!--
	Dimension by HTML5 UP
	html5up.net | @ajlkn
	Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
-->
<html>
 <head>
  <title>
   Dimension by HTML5 UP
  </title>
  <!-- <meta charset="utf-8" /> -->
  <!-- <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" /> -->
  <meta charset="utf-8"/>
  <meta content="width=device-width,initial-scale=1.0" name="viewport"/>
  <link href="../../assets/css/article.css" rel="stylesheet"/>
  <link href="https://cdn.bootcss.com/highlight.js/9.15.8/styles/github.min.css" rel="stylesheet"/>
  <noscript>
   <link href="../../assets/css/noscript.css" rel="stylesheet"/>
  </noscript>
 </head>
 <body>
  <div id="app">
  </div>
  <!-- built files will be auto injected -->
 </body>
 <body class="is-preload">
  <!-- Wrapper -->
  <div id="wrapper">
   <!-- Main -->
   <div id="main">
    <article id="article">
     <h1 id="soul">
      Soul网关源码解析（八）路由匹配初探
     </h1>
     <hr/>
     <h2 id="_1">
      简介
     </h2>
     <p>
      今日看看路由的匹配相关代码，查看HTTP的DividePlugin匹配
     </p>
     <h2 id="_2">
      示例运行
     </h2>
     <p>
      使用HTTP的示例，运行Soul-Admin，Soul-Bootstrap，Soul-Example-HTTP
     </p>
     <p>
      记得启动数据库
     </p>
     <p>
      ```shell script
docker run --name mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -d mysql:latest
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="o">&amp;</span><span class="n">ensp</span><span class="p">;</span><span class="o">&amp;</span><span class="n">ensp</span><span class="p">;</span><span class="o">&amp;</span><span class="n">ensp</span><span class="p">;</span><span class="o">&amp;</span><span class="n">ensp</span><span class="p">;</span><span class="o">&amp;</span><span class="n">ensp</span><span class="p">;</span><span class="n">其他的就不再赘述了</span><span class="err">，</span><span class="n">有问题可以参照前面的文章</span><span class="err">，</span><span class="n">看看有没有啥借鉴的</span><span class="w"></span>

<span class="err">##</span><span class="w"> </span><span class="n">源码Debug</span><span class="w"></span>
<span class="o">&amp;</span><span class="n">ensp</span><span class="p">;</span><span class="o">&amp;</span><span class="n">ensp</span><span class="p">;</span><span class="o">&amp;</span><span class="n">ensp</span><span class="p">;</span><span class="o">&amp;</span><span class="n">ensp</span><span class="p">;</span><span class="o">&amp;</span><span class="n">ensp</span><span class="p">;</span><span class="n">在番外篇</span><span class="err">：</span><span class="o">[</span><span class="n">Soul网关源码阅读番外篇（一） HTTP参数请求错误</span><span class="o">]</span><span class="p">(</span><span class="nl">https</span><span class="p">:</span><span class="o">//</span><span class="n">juejin</span><span class="p">.</span><span class="n">cn</span><span class="o">/</span><span class="n">post</span><span class="o">/</span><span class="mi">6918947689564471309</span><span class="p">)</span><span class="err">，</span><span class="n">我们知道了GlobalPlugin的重要性</span><span class="err">，</span><span class="n">其会将请求对应的真实是后台服务器路径写入Exchange中</span><span class="err">，</span><span class="n">我们先来摸一摸其具体细节</span><span class="err">：</span><span class="w"></span>

<span class="o">&amp;</span><span class="n">ensp</span><span class="p">;</span><span class="o">&amp;</span><span class="n">ensp</span><span class="p">;</span><span class="o">&amp;</span><span class="n">ensp</span><span class="p">;</span><span class="o">&amp;</span><span class="n">ensp</span><span class="p">;</span><span class="o">&amp;</span><span class="n">ensp</span><span class="p">;</span><span class="n">首先打上在类的execute中打上断点</span><span class="err">，</span><span class="n">访问</span><span class="err">：</span><span class="nl">http</span><span class="p">:</span><span class="o">//</span><span class="mf">127.0.0.1</span><span class="err">:</span><span class="mi">9195</span><span class="o">/</span><span class="n">http</span><span class="o">/</span><span class="k">order</span><span class="o">/</span><span class="n">findById</span><span class="vm">?</span><span class="n">id</span><span class="o">=</span><span class="mi">1111</span><span class="w"></span>

<span class="o">&amp;</span><span class="n">ensp</span><span class="p">;</span><span class="o">&amp;</span><span class="n">ensp</span><span class="p">;</span><span class="o">&amp;</span><span class="n">ensp</span><span class="p">;</span><span class="o">&amp;</span><span class="n">ensp</span><span class="p">;</span><span class="o">&amp;</span><span class="n">ensp</span><span class="p">;</span><span class="n">进入断点后</span><span class="err">，</span><span class="n">继续跟入</span><span class="w"></span>

<span class="err">```</span><span class="n">java</span><span class="w"></span>
<span class="k">public</span><span class="w"> </span><span class="k">class</span><span class="w"> </span><span class="n">GlobalPlugin</span><span class="w"> </span><span class="n">implements</span><span class="w"> </span><span class="n">SoulPlugin</span><span class="w"> </span><span class="err">{</span><span class="w"></span>
<span class="w">    </span><span class="p">......</span><span class="w"></span>

<span class="w">    </span><span class="nv">@Override</span><span class="w"></span>
<span class="w">    </span><span class="k">public</span><span class="w"> </span><span class="n">Mono</span><span class="o">&lt;</span><span class="n">Void</span><span class="o">&gt;</span><span class="w"> </span><span class="k">execute</span><span class="p">(</span><span class="n">final</span><span class="w"> </span><span class="n">ServerWebExchange</span><span class="w"> </span><span class="n">exchange</span><span class="p">,</span><span class="w"> </span><span class="n">final</span><span class="w"> </span><span class="n">SoulPluginChain</span><span class="w"> </span><span class="n">chain</span><span class="p">)</span><span class="w"> </span><span class="err">{</span><span class="w"></span>
<span class="w">        </span><span class="n">final</span><span class="w"> </span><span class="n">ServerHttpRequest</span><span class="w"> </span><span class="n">request</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">exchange</span><span class="p">.</span><span class="n">getRequest</span><span class="p">();</span><span class="w"></span>
<span class="w">        </span><span class="n">final</span><span class="w"> </span><span class="n">HttpHeaders</span><span class="w"> </span><span class="n">headers</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">request</span><span class="p">.</span><span class="n">getHeaders</span><span class="p">();</span><span class="w"></span>
<span class="w">        </span><span class="n">final</span><span class="w"> </span><span class="n">String</span><span class="w"> </span><span class="n">upgrade</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">headers</span><span class="p">.</span><span class="n">getFirst</span><span class="p">(</span><span class="ss">"Upgrade"</span><span class="p">);</span><span class="w"></span>
<span class="w">        </span><span class="n">SoulContext</span><span class="w"> </span><span class="n">soulContext</span><span class="p">;</span><span class="w"></span>
<span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">StringUtils</span><span class="p">.</span><span class="n">isBlank</span><span class="p">(</span><span class="n">upgrade</span><span class="p">)</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="err">!</span><span class="ss">"websocket"</span><span class="p">.</span><span class="k">equals</span><span class="p">(</span><span class="n">upgrade</span><span class="p">))</span><span class="w"> </span><span class="err">{</span><span class="w"></span>
<span class="w">            </span><span class="o">//</span><span class="w"> </span><span class="n">进入build函数</span><span class="err">，</span><span class="n">进行操作</span><span class="w"></span>
<span class="w">            </span><span class="n">soulContext</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">builder</span><span class="p">.</span><span class="n">build</span><span class="p">(</span><span class="n">exchange</span><span class="p">);</span><span class="w"></span>
<span class="w">        </span><span class="err">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="err">{</span><span class="w"></span>
<span class="w">            </span><span class="n">final</span><span class="w"> </span><span class="n">MultiValueMap</span><span class="o">&lt;</span><span class="n">String</span><span class="p">,</span><span class="w"> </span><span class="n">String</span><span class="o">&gt;</span><span class="w"> </span><span class="n">queryParams</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">request</span><span class="p">.</span><span class="n">getQueryParams</span><span class="p">();</span><span class="w"></span>
<span class="w">            </span><span class="n">soulContext</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">transformMap</span><span class="p">(</span><span class="n">queryParams</span><span class="p">);</span><span class="w"></span>
<span class="w">        </span><span class="err">}</span><span class="w"></span>
<span class="w">        </span><span class="n">exchange</span><span class="p">.</span><span class="n">getAttributes</span><span class="p">().</span><span class="n">put</span><span class="p">(</span><span class="n">Constants</span><span class="p">.</span><span class="n">CONTEXT</span><span class="p">,</span><span class="w"> </span><span class="n">soulContext</span><span class="p">);</span><span class="w"></span>
<span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="n">chain</span><span class="p">.</span><span class="k">execute</span><span class="p">(</span><span class="n">exchange</span><span class="p">);</span><span class="w"></span>
<span class="w">    </span><span class="err">}</span><span class="w"></span>
<span class="w">    </span><span class="p">......</span><span class="w"></span>
<span class="err">}</span><span class="w"></span>
</code></pre>
     </div>
     <p>
      跟进build里面去，里面首先获取了路径，进行请求类型判断，没有元数据则走到了默认的HTTP
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">DefaultSoulContextBuilder</span> <span class="kd">implements</span> <span class="n">SoulContextBuilder</span> <span class="p">{</span>

    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="n">SoulContext</span> <span class="nf">build</span><span class="p">(</span><span class="kd">final</span> <span class="n">ServerWebExchange</span> <span class="n">exchange</span><span class="p">)</span> <span class="p">{</span>
        <span class="kd">final</span> <span class="n">ServerHttpRequest</span> <span class="n">request</span> <span class="o">=</span> <span class="n">exchange</span><span class="p">.</span><span class="na">getRequest</span><span class="p">();</span>
        <span class="c1">// path = /http/order/findById</span>
        <span class="n">String</span> <span class="n">path</span> <span class="o">=</span> <span class="n">request</span><span class="p">.</span><span class="na">getURI</span><span class="p">().</span><span class="na">getPath</span><span class="p">();</span>
        <span class="n">MetaData</span> <span class="n">metaData</span> <span class="o">=</span> <span class="n">MetaDataCache</span><span class="p">.</span><span class="na">getInstance</span><span class="p">().</span><span class="na">obtain</span><span class="p">(</span><span class="n">path</span><span class="p">);</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">Objects</span><span class="p">.</span><span class="na">nonNull</span><span class="p">(</span><span class="n">metaData</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="n">metaData</span><span class="p">.</span><span class="na">getEnabled</span><span class="p">())</span> <span class="p">{</span>
            <span class="n">exchange</span><span class="p">.</span><span class="na">getAttributes</span><span class="p">().</span><span class="na">put</span><span class="p">(</span><span class="n">Constants</span><span class="p">.</span><span class="na">META_DATA</span><span class="p">,</span> <span class="n">metaData</span><span class="p">);</span>
        <span class="p">}</span>
        <span class="c1">// 进入 transform 函数</span>
        <span class="k">return</span> <span class="n">transform</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="n">metaData</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="kd">private</span> <span class="n">SoulContext</span> <span class="nf">transform</span><span class="p">(</span><span class="kd">final</span> <span class="n">ServerHttpRequest</span> <span class="n">request</span><span class="p">,</span> <span class="kd">final</span> <span class="n">MetaData</span> <span class="n">metaData</span><span class="p">)</span> <span class="p">{</span>
        <span class="kd">final</span> <span class="n">String</span> <span class="n">appKey</span> <span class="o">=</span> <span class="n">request</span><span class="p">.</span><span class="na">getHeaders</span><span class="p">().</span><span class="na">getFirst</span><span class="p">(</span><span class="n">Constants</span><span class="p">.</span><span class="na">APP_KEY</span><span class="p">);</span>
        <span class="kd">final</span> <span class="n">String</span> <span class="n">sign</span> <span class="o">=</span> <span class="n">request</span><span class="p">.</span><span class="na">getHeaders</span><span class="p">().</span><span class="na">getFirst</span><span class="p">(</span><span class="n">Constants</span><span class="p">.</span><span class="na">SIGN</span><span class="p">);</span>
        <span class="kd">final</span> <span class="n">String</span> <span class="n">timestamp</span> <span class="o">=</span> <span class="n">request</span><span class="p">.</span><span class="na">getHeaders</span><span class="p">().</span><span class="na">getFirst</span><span class="p">(</span><span class="n">Constants</span><span class="p">.</span><span class="na">TIMESTAMP</span><span class="p">);</span>
        <span class="n">SoulContext</span> <span class="n">soulContext</span> <span class="o">=</span> <span class="k">new</span> <span class="n">SoulContext</span><span class="p">();</span>
        <span class="c1">// path = /http/order/findById</span>
        <span class="n">String</span> <span class="n">path</span> <span class="o">=</span> <span class="n">request</span><span class="p">.</span><span class="na">getURI</span><span class="p">().</span><span class="na">getPath</span><span class="p">();</span>
        <span class="n">soulContext</span><span class="p">.</span><span class="na">setPath</span><span class="p">(</span><span class="n">path</span><span class="p">);</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">Objects</span><span class="p">.</span><span class="na">nonNull</span><span class="p">(</span><span class="n">metaData</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="n">metaData</span><span class="p">.</span><span class="na">getEnabled</span><span class="p">())</span> <span class="p">{</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">RpcTypeEnum</span><span class="p">.</span><span class="na">SPRING_CLOUD</span><span class="p">.</span><span class="na">getName</span><span class="p">().</span><span class="na">equals</span><span class="p">(</span><span class="n">metaData</span><span class="p">.</span><span class="na">getRpcType</span><span class="p">()))</span> <span class="p">{</span>
                <span class="n">setSoulContextByHttp</span><span class="p">(</span><span class="n">soulContext</span><span class="p">,</span> <span class="n">path</span><span class="p">);</span>
                <span class="n">soulContext</span><span class="p">.</span><span class="na">setRpcType</span><span class="p">(</span><span class="n">metaData</span><span class="p">.</span><span class="na">getRpcType</span><span class="p">());</span>
            <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">RpcTypeEnum</span><span class="p">.</span><span class="na">DUBBO</span><span class="p">.</span><span class="na">getName</span><span class="p">().</span><span class="na">equals</span><span class="p">(</span><span class="n">metaData</span><span class="p">.</span><span class="na">getRpcType</span><span class="p">()))</span> <span class="p">{</span>
                <span class="n">setSoulContextByDubbo</span><span class="p">(</span><span class="n">soulContext</span><span class="p">,</span> <span class="n">metaData</span><span class="p">);</span>
            <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">RpcTypeEnum</span><span class="p">.</span><span class="na">SOFA</span><span class="p">.</span><span class="na">getName</span><span class="p">().</span><span class="na">equals</span><span class="p">(</span><span class="n">metaData</span><span class="p">.</span><span class="na">getRpcType</span><span class="p">()))</span> <span class="p">{</span>
                <span class="n">setSoulContextBySofa</span><span class="p">(</span><span class="n">soulContext</span><span class="p">,</span> <span class="n">metaData</span><span class="p">);</span>
            <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">RpcTypeEnum</span><span class="p">.</span><span class="na">TARS</span><span class="p">.</span><span class="na">getName</span><span class="p">().</span><span class="na">equals</span><span class="p">(</span><span class="n">metaData</span><span class="p">.</span><span class="na">getRpcType</span><span class="p">()))</span> <span class="p">{</span>
                <span class="n">setSoulContextByTars</span><span class="p">(</span><span class="n">soulContext</span><span class="p">,</span> <span class="n">metaData</span><span class="p">);</span>
            <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
                <span class="n">setSoulContextByHttp</span><span class="p">(</span><span class="n">soulContext</span><span class="p">,</span> <span class="n">path</span><span class="p">);</span>
                <span class="n">soulContext</span><span class="p">.</span><span class="na">setRpcType</span><span class="p">(</span><span class="n">RpcTypeEnum</span><span class="p">.</span><span class="na">HTTP</span><span class="p">.</span><span class="na">getName</span><span class="p">());</span>
            <span class="p">}</span>
        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
            <span class="c1">// 来打这，进行HTTP设置</span>
            <span class="n">setSoulContextByHttp</span><span class="p">(</span><span class="n">soulContext</span><span class="p">,</span> <span class="n">path</span><span class="p">);</span>
            <span class="n">soulContext</span><span class="p">.</span><span class="na">setRpcType</span><span class="p">(</span><span class="n">RpcTypeEnum</span><span class="p">.</span><span class="na">HTTP</span><span class="p">.</span><span class="na">getName</span><span class="p">());</span>
        <span class="p">}</span>
        <span class="n">soulContext</span><span class="p">.</span><span class="na">setAppKey</span><span class="p">(</span><span class="n">appKey</span><span class="p">);</span>
        <span class="n">soulContext</span><span class="p">.</span><span class="na">setSign</span><span class="p">(</span><span class="n">sign</span><span class="p">);</span>
        <span class="n">soulContext</span><span class="p">.</span><span class="na">setTimestamp</span><span class="p">(</span><span class="n">timestamp</span><span class="p">);</span>
        <span class="n">soulContext</span><span class="p">.</span><span class="na">setStartDateTime</span><span class="p">(</span><span class="n">LocalDateTime</span><span class="p">.</span><span class="na">now</span><span class="p">());</span>
        <span class="n">Optional</span><span class="p">.</span><span class="na">ofNullable</span><span class="p">(</span><span class="n">request</span><span class="p">.</span><span class="na">getMethod</span><span class="p">()).</span><span class="na">ifPresent</span><span class="p">(</span><span class="n">httpMethod</span> <span class="o">-&gt;</span> <span class="n">soulContext</span><span class="p">.</span><span class="na">setHttpMethod</span><span class="p">(</span><span class="n">httpMethod</span><span class="p">.</span><span class="na">name</span><span class="p">()));</span>
        <span class="k">return</span> <span class="n">soulContext</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="kd">private</span> <span class="kt">void</span> <span class="nf">setSoulContextByHttp</span><span class="p">(</span><span class="kd">final</span> <span class="n">SoulContext</span> <span class="n">soulContext</span><span class="p">,</span> <span class="kd">final</span> <span class="n">String</span> <span class="n">path</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">String</span> <span class="n">contextPath</span> <span class="o">=</span> <span class="s">"/"</span><span class="p">;</span>
        <span class="c1">// 是一个列表，值是：http, order, findById</span>
        <span class="n">String</span><span class="o">[]</span> <span class="n">splitList</span> <span class="o">=</span> <span class="n">StringUtils</span><span class="p">.</span><span class="na">split</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="s">"/"</span><span class="p">);</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">splitList</span><span class="p">.</span><span class="na">length</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
            <span class="c1">// 这个应该是前缀的意思，并且只取第一个，值是：/http</span>
            <span class="n">contextPath</span> <span class="o">=</span> <span class="n">contextPath</span><span class="p">.</span><span class="na">concat</span><span class="p">(</span><span class="n">splitList</span><span class="o">[</span><span class="mi">0</span><span class="o">]</span><span class="p">);</span>
        <span class="p">}</span>
        <span class="c1">// 取后面的字符串，得到：/order/findById</span>
        <span class="n">String</span> <span class="n">realUrl</span> <span class="o">=</span> <span class="n">path</span><span class="p">.</span><span class="na">substring</span><span class="p">(</span><span class="n">contextPath</span><span class="p">.</span><span class="na">length</span><span class="p">());</span>
        <span class="n">soulContext</span><span class="p">.</span><span class="na">setContextPath</span><span class="p">(</span><span class="n">contextPath</span><span class="p">);</span>
        <span class="n">soulContext</span><span class="p">.</span><span class="na">setModule</span><span class="p">(</span><span class="n">contextPath</span><span class="p">);</span>
        <span class="n">soulContext</span><span class="p">.</span><span class="na">setMethod</span><span class="p">(</span><span class="n">realUrl</span><span class="p">);</span>
        <span class="n">soulContext</span><span class="p">.</span><span class="na">setRealUrl</span><span class="p">(</span><span class="n">realUrl</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre>
     </div>
     <p>
      在最后一个函数中，我们看到了具体设置realURL的代码，其大致思路，如上面代码总描述的一样
     </p>
     <p>
      这里就有个小疑问，前缀也就是只能是 /xxx 之类的，如果是 /xxx/xxx 那请求后面是否会出问题
     </p>
     <p>
      我们做了一个小实验，设置一个选择器为条件为：/more/prefix,一个规则为：/more/prefix/baidu，都是相等条件
     </p>
     <p>
      下面Debug来看下GlobalPlugin的解析结果，如下，明显不是我们想要的，所有这里初步猜测不能选择器不能使用两级前缀，不然可能会出问题
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="err">contextPath = /more</span>
<span class="err">realURL = /prefix/baidu</span>
</code></pre>
     </div>
     <p>
      下面我继续看下，DividePlugin的匹配详情，首先打入断点在 AbstractSoulPlugin,执行匹配逻辑
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="kd">public</span> <span class="kd">abstract</span> <span class="kd">class</span> <span class="nc">AbstractSoulPlugin</span> <span class="kd">implements</span> <span class="n">SoulPlugin</span> <span class="p">{</span>
    <span class="p">......</span>
    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="n">Mono</span><span class="o">&lt;</span><span class="n">Void</span><span class="o">&gt;</span> <span class="nf">execute</span><span class="p">(</span><span class="kd">final</span> <span class="n">ServerWebExchange</span> <span class="n">exchange</span><span class="p">,</span> <span class="kd">final</span> <span class="n">SoulPluginChain</span> <span class="n">chain</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">String</span> <span class="n">pluginName</span> <span class="o">=</span> <span class="n">named</span><span class="p">();</span>
        <span class="kd">final</span> <span class="n">PluginData</span> <span class="n">pluginData</span> <span class="o">=</span> <span class="n">BaseDataCache</span><span class="p">.</span><span class="na">getInstance</span><span class="p">().</span><span class="na">obtainPluginData</span><span class="p">(</span><span class="n">pluginName</span><span class="p">);</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">pluginData</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">&amp;&amp;</span> <span class="n">pluginData</span><span class="p">.</span><span class="na">getEnabled</span><span class="p">())</span> <span class="p">{</span>
            <span class="kd">final</span> <span class="n">Collection</span><span class="o">&lt;</span><span class="n">SelectorData</span><span class="o">&gt;</span> <span class="n">selectors</span> <span class="o">=</span> <span class="n">BaseDataCache</span><span class="p">.</span><span class="na">getInstance</span><span class="p">().</span><span class="na">obtainSelectorData</span><span class="p">(</span><span class="n">pluginName</span><span class="p">);</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">CollectionUtils</span><span class="p">.</span><span class="na">isEmpty</span><span class="p">(</span><span class="n">selectors</span><span class="p">))</span> <span class="p">{</span>
                <span class="k">return</span> <span class="n">handleSelectorIsNull</span><span class="p">(</span><span class="n">pluginName</span><span class="p">,</span> <span class="n">exchange</span><span class="p">,</span> <span class="n">chain</span><span class="p">);</span>
            <span class="p">}</span>
            <span class="c1">// use /http/order/findById</span>
            <span class="c1">// 这里首先进行选择器的匹配，我们看下选择器如果的匹配细节</span>
            <span class="kd">final</span> <span class="n">SelectorData</span> <span class="n">selectorData</span> <span class="o">=</span> <span class="n">matchSelector</span><span class="p">(</span><span class="n">exchange</span><span class="p">,</span> <span class="n">selectors</span><span class="p">);</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">Objects</span><span class="p">.</span><span class="na">isNull</span><span class="p">(</span><span class="n">selectorData</span><span class="p">))</span> <span class="p">{</span>
                <span class="k">return</span> <span class="n">handleSelectorIsNull</span><span class="p">(</span><span class="n">pluginName</span><span class="p">,</span> <span class="n">exchange</span><span class="p">,</span> <span class="n">chain</span><span class="p">);</span>
            <span class="p">}</span>
            <span class="n">selectorLog</span><span class="p">(</span><span class="n">selectorData</span><span class="p">,</span> <span class="n">pluginName</span><span class="p">);</span>
            <span class="kd">final</span> <span class="n">List</span><span class="o">&lt;</span><span class="n">RuleData</span><span class="o">&gt;</span> <span class="n">rules</span> <span class="o">=</span> <span class="n">BaseDataCache</span><span class="p">.</span><span class="na">getInstance</span><span class="p">().</span><span class="na">obtainRuleData</span><span class="p">(</span><span class="n">selectorData</span><span class="p">.</span><span class="na">getId</span><span class="p">());</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">CollectionUtils</span><span class="p">.</span><span class="na">isEmpty</span><span class="p">(</span><span class="n">rules</span><span class="p">))</span> <span class="p">{</span>
                <span class="k">return</span> <span class="n">handleRuleIsNull</span><span class="p">(</span><span class="n">pluginName</span><span class="p">,</span> <span class="n">exchange</span><span class="p">,</span> <span class="n">chain</span><span class="p">);</span>
            <span class="p">}</span>
            <span class="n">RuleData</span> <span class="n">rule</span><span class="p">;</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">selectorData</span><span class="p">.</span><span class="na">getType</span><span class="p">()</span> <span class="o">==</span> <span class="n">SelectorTypeEnum</span><span class="p">.</span><span class="na">FULL_FLOW</span><span class="p">.</span><span class="na">getCode</span><span class="p">())</span> <span class="p">{</span>
                <span class="c1">//get last</span>
                <span class="n">rule</span> <span class="o">=</span> <span class="n">rules</span><span class="p">.</span><span class="na">get</span><span class="p">(</span><span class="n">rules</span><span class="p">.</span><span class="na">size</span><span class="p">()</span> <span class="o">-</span> <span class="mi">1</span><span class="p">);</span>
            <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
                <span class="n">rule</span> <span class="o">=</span> <span class="n">matchRule</span><span class="p">(</span><span class="n">exchange</span><span class="p">,</span> <span class="n">rules</span><span class="p">);</span>
            <span class="p">}</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">Objects</span><span class="p">.</span><span class="na">isNull</span><span class="p">(</span><span class="n">rule</span><span class="p">))</span> <span class="p">{</span>
                <span class="k">return</span> <span class="n">handleRuleIsNull</span><span class="p">(</span><span class="n">pluginName</span><span class="p">,</span> <span class="n">exchange</span><span class="p">,</span> <span class="n">chain</span><span class="p">);</span>
            <span class="p">}</span>
            <span class="n">ruleLog</span><span class="p">(</span><span class="n">rule</span><span class="p">,</span> <span class="n">pluginName</span><span class="p">);</span>
            <span class="k">return</span> <span class="n">doExecute</span><span class="p">(</span><span class="n">exchange</span><span class="p">,</span> <span class="n">chain</span><span class="p">,</span> <span class="n">selectorData</span><span class="p">,</span> <span class="n">rule</span><span class="p">);</span>
        <span class="p">}</span>
        <span class="k">return</span> <span class="n">chain</span><span class="p">.</span><span class="na">execute</span><span class="p">(</span><span class="n">exchange</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="kd">private</span> <span class="n">SelectorData</span> <span class="nf">matchSelector</span><span class="p">(</span><span class="kd">final</span> <span class="n">ServerWebExchange</span> <span class="n">exchange</span><span class="p">,</span> <span class="kd">final</span> <span class="n">Collection</span><span class="o">&lt;</span><span class="n">SelectorData</span><span class="o">&gt;</span> <span class="n">selectors</span><span class="p">)</span> <span class="p">{</span>
        <span class="c1">// 循环每个选择器，看是否能匹配得上，findFirst的意思是否多个匹配上就要第一个？</span>
        <span class="k">return</span> <span class="n">selectors</span><span class="p">.</span><span class="na">stream</span><span class="p">()</span>
                <span class="p">.</span><span class="na">filter</span><span class="p">(</span><span class="n">selector</span> <span class="o">-&gt;</span> <span class="n">selector</span><span class="p">.</span><span class="na">getEnabled</span><span class="p">()</span> <span class="o">&amp;&amp;</span> <span class="n">filterSelector</span><span class="p">(</span><span class="n">selector</span><span class="p">,</span> <span class="n">exchange</span><span class="p">))</span>
                <span class="p">.</span><span class="na">findFirst</span><span class="p">().</span><span class="na">orElse</span><span class="p">(</span><span class="kc">null</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="kd">private</span> <span class="n">Boolean</span> <span class="nf">filterSelector</span><span class="p">(</span><span class="kd">final</span> <span class="n">SelectorData</span> <span class="n">selector</span><span class="p">,</span> <span class="kd">final</span> <span class="n">ServerWebExchange</span> <span class="n">exchange</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">selector</span><span class="p">.</span><span class="na">getType</span><span class="p">()</span> <span class="o">==</span> <span class="n">SelectorTypeEnum</span><span class="p">.</span><span class="na">CUSTOM_FLOW</span><span class="p">.</span><span class="na">getCode</span><span class="p">())</span> <span class="p">{</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">CollectionUtils</span><span class="p">.</span><span class="na">isEmpty</span><span class="p">(</span><span class="n">selector</span><span class="p">.</span><span class="na">getConditionList</span><span class="p">()))</span> <span class="p">{</span>
                <span class="k">return</span> <span class="kc">false</span><span class="p">;</span>
            <span class="p">}</span>
            <span class="c1">// 使用匹配策略工具进行匹配，我们进行跟下去</span>
            <span class="k">return</span> <span class="n">MatchStrategyUtils</span><span class="p">.</span><span class="na">match</span><span class="p">(</span><span class="n">selector</span><span class="p">.</span><span class="na">getMatchMode</span><span class="p">(),</span> <span class="n">selector</span><span class="p">.</span><span class="na">getConditionList</span><span class="p">(),</span> <span class="n">exchange</span><span class="p">);</span>
        <span class="p">}</span>
        <span class="k">return</span> <span class="kc">true</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="kd">private</span> <span class="n">RuleData</span> <span class="nf">matchRule</span><span class="p">(</span><span class="kd">final</span> <span class="n">ServerWebExchange</span> <span class="n">exchange</span><span class="p">,</span> <span class="kd">final</span> <span class="n">Collection</span><span class="o">&lt;</span><span class="n">RuleData</span><span class="o">&gt;</span> <span class="n">rules</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">return</span> <span class="n">rules</span><span class="p">.</span><span class="na">stream</span><span class="p">()</span>
                <span class="p">.</span><span class="na">filter</span><span class="p">(</span><span class="n">rule</span> <span class="o">-&gt;</span> <span class="n">filterRule</span><span class="p">(</span><span class="n">rule</span><span class="p">,</span> <span class="n">exchange</span><span class="p">))</span>
                <span class="p">.</span><span class="na">findFirst</span><span class="p">().</span><span class="na">orElse</span><span class="p">(</span><span class="kc">null</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="kd">private</span> <span class="n">Boolean</span> <span class="nf">filterRule</span><span class="p">(</span><span class="kd">final</span> <span class="n">RuleData</span> <span class="n">ruleData</span><span class="p">,</span> <span class="kd">final</span> <span class="n">ServerWebExchange</span> <span class="n">exchange</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">return</span> <span class="n">ruleData</span><span class="p">.</span><span class="na">getEnabled</span><span class="p">()</span> <span class="o">&amp;&amp;</span> <span class="n">MatchStrategyUtils</span><span class="p">.</span><span class="na">match</span><span class="p">(</span><span class="n">ruleData</span><span class="p">.</span><span class="na">getMatchMode</span><span class="p">(),</span> <span class="n">ruleData</span><span class="p">.</span><span class="na">getConditionDataList</span><span class="p">(),</span> <span class="n">exchange</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="p">......</span>
<span class="p">}</span>
</code></pre>
     </div>
     <p>
      继续跟到匹配策略工具的类中，它有and和or的匹配策略，判断策略，构造相关策略类后进行调用
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">MatchStrategyUtils</span> <span class="p">{</span>

    <span class="kd">public</span> <span class="kd">static</span> <span class="kt">boolean</span> <span class="nf">match</span><span class="p">(</span><span class="kd">final</span> <span class="n">Integer</span> <span class="n">strategy</span><span class="p">,</span> <span class="kd">final</span> <span class="n">List</span><span class="o">&lt;</span><span class="n">ConditionData</span><span class="o">&gt;</span> <span class="n">conditionDataList</span><span class="p">,</span> <span class="kd">final</span> <span class="n">ServerWebExchange</span> <span class="n">exchange</span><span class="p">)</span> <span class="p">{</span>
        <span class="c1">// and 策略，构造and策略类，进行匹配；继续跟进match</span>
        <span class="n">String</span> <span class="n">matchMode</span> <span class="o">=</span> <span class="n">MatchModeEnum</span><span class="p">.</span><span class="na">getMatchModeByCode</span><span class="p">(</span><span class="n">strategy</span><span class="p">);</span>
        <span class="n">MatchStrategy</span> <span class="n">matchStrategy</span> <span class="o">=</span> <span class="n">ExtensionLoader</span><span class="p">.</span><span class="na">getExtensionLoader</span><span class="p">(</span><span class="n">MatchStrategy</span><span class="p">.</span><span class="na">class</span><span class="p">).</span><span class="na">getJoin</span><span class="p">(</span><span class="n">matchMode</span><span class="p">);</span>
        <span class="k">return</span> <span class="n">matchStrategy</span><span class="p">.</span><span class="na">match</span><span class="p">(</span><span class="n">conditionDataList</span><span class="p">,</span> <span class="n">exchange</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre>
     </div>
     <p>
      进行跟到judge函数中
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">AndMatchStrategy</span> <span class="kd">extends</span> <span class="n">AbstractMatchStrategy</span> <span class="kd">implements</span> <span class="n">MatchStrategy</span> <span class="p">{</span>

    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="n">Boolean</span> <span class="nf">match</span><span class="p">(</span><span class="kd">final</span> <span class="n">List</span><span class="o">&lt;</span><span class="n">ConditionData</span><span class="o">&gt;</span> <span class="n">conditionDataList</span><span class="p">,</span> <span class="kd">final</span> <span class="n">ServerWebExchange</span> <span class="n">exchange</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">return</span> <span class="n">conditionDataList</span>
                <span class="p">.</span><span class="na">stream</span><span class="p">()</span>
                <span class="p">.</span><span class="na">allMatch</span><span class="p">(</span><span class="n">condition</span> <span class="o">-&gt;</span> <span class="n">OperatorJudgeFactory</span><span class="p">.</span><span class="na">judge</span><span class="p">(</span><span class="n">condition</span><span class="p">,</span> <span class="n">buildRealData</span><span class="p">(</span><span class="n">condition</span><span class="p">,</span> <span class="n">exchange</span><span class="p">)));</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre>
     </div>
     <p>
      再根据judge，有点复杂感觉......
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">OperatorJudgeFactory</span> <span class="p">{</span>

    <span class="kd">public</span> <span class="kd">static</span> <span class="n">Boolean</span> <span class="nf">judge</span><span class="p">(</span><span class="kd">final</span> <span class="n">ConditionData</span> <span class="n">conditionData</span><span class="p">,</span> <span class="kd">final</span> <span class="n">String</span> <span class="n">realData</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">Objects</span><span class="p">.</span><span class="na">isNull</span><span class="p">(</span><span class="n">conditionData</span><span class="p">)</span> <span class="o">||</span> <span class="n">StringUtils</span><span class="p">.</span><span class="na">isBlank</span><span class="p">(</span><span class="n">realData</span><span class="p">))</span> <span class="p">{</span>
            <span class="k">return</span> <span class="kc">false</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="k">return</span> <span class="n">OPERATOR_JUDGE_MAP</span><span class="p">.</span><span class="na">get</span><span class="p">(</span><span class="n">conditionData</span><span class="p">.</span><span class="na">getOperator</span><span class="p">()).</span><span class="na">judge</span><span class="p">(</span><span class="n">conditionData</span><span class="p">,</span> <span class="n">realData</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre>
     </div>
     <p>
      一层又一层，继续跟进match函数中
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">MatchOperatorJudge</span> <span class="kd">implements</span> <span class="n">OperatorJudge</span> <span class="p">{</span>

    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="n">Boolean</span> <span class="nf">judge</span><span class="p">(</span><span class="kd">final</span> <span class="n">ConditionData</span> <span class="n">conditionData</span><span class="p">,</span> <span class="kd">final</span> <span class="n">String</span> <span class="n">realData</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">Objects</span><span class="p">.</span><span class="na">equals</span><span class="p">(</span><span class="n">ParamTypeEnum</span><span class="p">.</span><span class="na">URI</span><span class="p">.</span><span class="na">getName</span><span class="p">(),</span> <span class="n">conditionData</span><span class="p">.</span><span class="na">getParamType</span><span class="p">()))</span> <span class="p">{</span>
            <span class="k">return</span> <span class="n">PathMatchUtils</span><span class="p">.</span><span class="na">match</span><span class="p">(</span><span class="n">conditionData</span><span class="p">.</span><span class="na">getParamValue</span><span class="p">().</span><span class="na">trim</span><span class="p">(),</span> <span class="n">realData</span><span class="p">);</span>
        <span class="p">}</span>
        <span class="k">return</span> <span class="n">realData</span><span class="p">.</span><span class="na">contains</span><span class="p">(</span><span class="n">conditionData</span><span class="p">.</span><span class="na">getParamValue</span><span class="p">().</span><span class="na">trim</span><span class="p">());</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre>
     </div>
     <p>
      在这终于看到了具体的逻辑实现了，大致可以看出这是个字符串匹配
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">PathMatchUtils</span> <span class="p">{</span>

    <span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="n">AntPathMatcher</span> <span class="n">MATCHER</span> <span class="o">=</span> <span class="k">new</span> <span class="n">AntPathMatcher</span><span class="p">();</span>

    <span class="kd">public</span> <span class="kd">static</span> <span class="kt">boolean</span> <span class="nf">match</span><span class="p">(</span><span class="kd">final</span> <span class="n">String</span> <span class="n">matchUrls</span><span class="p">,</span> <span class="kd">final</span> <span class="n">String</span> <span class="n">path</span><span class="p">)</span> <span class="p">{</span>
        <span class="c1">// matchUrls = /http/** , path = /http/order/findById</span>
        <span class="k">return</span> <span class="n">Splitter</span><span class="p">.</span><span class="na">on</span><span class="p">(</span><span class="s">","</span><span class="p">).</span><span class="na">omitEmptyStrings</span><span class="p">().</span><span class="na">trimResults</span><span class="p">().</span><span class="na">splitToList</span><span class="p">(</span><span class="n">matchUrls</span><span class="p">).</span><span class="na">stream</span><span class="p">().</span><span class="na">anyMatch</span><span class="p">(</span><span class="n">url</span> <span class="o">-&gt;</span> <span class="n">reg</span><span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="n">path</span><span class="p">));</span>
    <span class="p">}</span>

<span class="p">}</span>
</code></pre>
     </div>
     <p>
      选择器的匹配大致就是这些，可以但到进行匹配，其中的过程还挺复杂的，隐约能感受到一点设计的思想，有点逐步拆分的感觉。这块具体的分析，后面有时间再看看
     </p>
     <p>
      选择器匹配上以后，就进行到规则的匹配了，规则的匹配和选择器的匹配都是使用的这个匹配策略类进行匹配的，就是换行匹配的字符串罢了，这里就不详述了
     </p>
     <p>
      需要注意的一点是，规则匹配是使用请求的完整路径和规则的完整路径进行匹配的，没有截取之类的，也就是选择器和规则的路径设置存在高度的关联性，前缀可以说必须进行继承，这样感觉可能会导致一些灵活性的丧失
     </p>
     <p>
      继续来看 DividePlugin 插件，在下面的注释中可以看到 domain + readUrl 组合成了针对后端服务请求的url
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">DividePlugin</span> <span class="kd">extends</span> <span class="n">AbstractSoulPlugin</span> <span class="p">{</span>

    <span class="nd">@Override</span>
    <span class="kd">protected</span> <span class="n">Mono</span><span class="o">&lt;</span><span class="n">Void</span><span class="o">&gt;</span> <span class="nf">doExecute</span><span class="p">(</span><span class="kd">final</span> <span class="n">ServerWebExchange</span> <span class="n">exchange</span><span class="p">,</span> <span class="kd">final</span> <span class="n">SoulPluginChain</span> <span class="n">chain</span><span class="p">,</span> <span class="kd">final</span> <span class="n">SelectorData</span> <span class="n">selector</span><span class="p">,</span> <span class="kd">final</span> <span class="n">RuleData</span> <span class="n">rule</span><span class="p">)</span> <span class="p">{</span>
        <span class="kd">final</span> <span class="n">SoulContext</span> <span class="n">soulContext</span> <span class="o">=</span> <span class="n">exchange</span><span class="p">.</span><span class="na">getAttribute</span><span class="p">(</span><span class="n">Constants</span><span class="p">.</span><span class="na">CONTEXT</span><span class="p">);</span>
        <span class="k">assert</span> <span class="n">soulContext</span> <span class="o">!=</span> <span class="kc">null</span><span class="p">;</span>
        <span class="kd">final</span> <span class="n">DivideRuleHandle</span> <span class="n">ruleHandle</span> <span class="o">=</span> <span class="n">GsonUtils</span><span class="p">.</span><span class="na">getInstance</span><span class="p">().</span><span class="na">fromJson</span><span class="p">(</span><span class="n">rule</span><span class="p">.</span><span class="na">getHandle</span><span class="p">(),</span> <span class="n">DivideRuleHandle</span><span class="p">.</span><span class="na">class</span><span class="p">);</span>
        <span class="kd">final</span> <span class="n">List</span><span class="o">&lt;</span><span class="n">DivideUpstream</span><span class="o">&gt;</span> <span class="n">upstreamList</span> <span class="o">=</span> <span class="n">UpstreamCacheManager</span><span class="p">.</span><span class="na">getInstance</span><span class="p">().</span><span class="na">findUpstreamListBySelectorId</span><span class="p">(</span><span class="n">selector</span><span class="p">.</span><span class="na">getId</span><span class="p">());</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">CollectionUtils</span><span class="p">.</span><span class="na">isEmpty</span><span class="p">(</span><span class="n">upstreamList</span><span class="p">))</span> <span class="p">{</span>
            <span class="n">log</span><span class="p">.</span><span class="na">error</span><span class="p">(</span><span class="s">"divide upstream configuration error： {}"</span><span class="p">,</span> <span class="n">rule</span><span class="p">.</span><span class="na">toString</span><span class="p">());</span>
            <span class="n">Object</span> <span class="n">error</span> <span class="o">=</span> <span class="n">SoulResultWrap</span><span class="p">.</span><span class="na">error</span><span class="p">(</span><span class="n">SoulResultEnum</span><span class="p">.</span><span class="na">CANNOT_FIND_URL</span><span class="p">.</span><span class="na">getCode</span><span class="p">(),</span> <span class="n">SoulResultEnum</span><span class="p">.</span><span class="na">CANNOT_FIND_URL</span><span class="p">.</span><span class="na">getMsg</span><span class="p">(),</span> <span class="kc">null</span><span class="p">);</span>
            <span class="k">return</span> <span class="n">WebFluxResultUtils</span><span class="p">.</span><span class="na">result</span><span class="p">(</span><span class="n">exchange</span><span class="p">,</span> <span class="n">error</span><span class="p">);</span>
        <span class="p">}</span>
        <span class="kd">final</span> <span class="n">String</span> <span class="n">ip</span> <span class="o">=</span> <span class="n">Objects</span><span class="p">.</span><span class="na">requireNonNull</span><span class="p">(</span><span class="n">exchange</span><span class="p">.</span><span class="na">getRequest</span><span class="p">().</span><span class="na">getRemoteAddress</span><span class="p">()).</span><span class="na">getAddress</span><span class="p">().</span><span class="na">getHostAddress</span><span class="p">();</span>
        <span class="n">DivideUpstream</span> <span class="n">divideUpstream</span> <span class="o">=</span> <span class="n">LoadBalanceUtils</span><span class="p">.</span><span class="na">selector</span><span class="p">(</span><span class="n">upstreamList</span><span class="p">,</span> <span class="n">ruleHandle</span><span class="p">.</span><span class="na">getLoadBalance</span><span class="p">(),</span> <span class="n">ip</span><span class="p">);</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">Objects</span><span class="p">.</span><span class="na">isNull</span><span class="p">(</span><span class="n">divideUpstream</span><span class="p">))</span> <span class="p">{</span>
            <span class="n">log</span><span class="p">.</span><span class="na">error</span><span class="p">(</span><span class="s">"divide has no upstream"</span><span class="p">);</span>
            <span class="n">Object</span> <span class="n">error</span> <span class="o">=</span> <span class="n">SoulResultWrap</span><span class="p">.</span><span class="na">error</span><span class="p">(</span><span class="n">SoulResultEnum</span><span class="p">.</span><span class="na">CANNOT_FIND_URL</span><span class="p">.</span><span class="na">getCode</span><span class="p">(),</span> <span class="n">SoulResultEnum</span><span class="p">.</span><span class="na">CANNOT_FIND_URL</span><span class="p">.</span><span class="na">getMsg</span><span class="p">(),</span> <span class="kc">null</span><span class="p">);</span>
            <span class="k">return</span> <span class="n">WebFluxResultUtils</span><span class="p">.</span><span class="na">result</span><span class="p">(</span><span class="n">exchange</span><span class="p">,</span> <span class="n">error</span><span class="p">);</span>
        <span class="p">}</span>
        <span class="c1">// set the http url : http://192.168.101.104:8188</span>
        <span class="n">String</span> <span class="n">domain</span> <span class="o">=</span> <span class="n">buildDomain</span><span class="p">(</span><span class="n">divideUpstream</span><span class="p">);</span>
        <span class="c1">// get real url : http://192.168.101.104:8188/order/findById?id=1111</span>
        <span class="n">String</span> <span class="n">realURL</span> <span class="o">=</span> <span class="n">buildRealURL</span><span class="p">(</span><span class="n">domain</span><span class="p">,</span> <span class="n">soulContext</span><span class="p">,</span> <span class="n">exchange</span><span class="p">);</span>
        <span class="n">exchange</span><span class="p">.</span><span class="na">getAttributes</span><span class="p">().</span><span class="na">put</span><span class="p">(</span><span class="n">Constants</span><span class="p">.</span><span class="na">HTTP_URL</span><span class="p">,</span> <span class="n">realURL</span><span class="p">);</span>
        <span class="n">exchange</span><span class="p">.</span><span class="na">getAttributes</span><span class="p">().</span><span class="na">put</span><span class="p">(</span><span class="n">Constants</span><span class="p">.</span><span class="na">HTTP_TIME_OUT</span><span class="p">,</span> <span class="n">ruleHandle</span><span class="p">.</span><span class="na">getTimeout</span><span class="p">());</span>
        <span class="n">exchange</span><span class="p">.</span><span class="na">getAttributes</span><span class="p">().</span><span class="na">put</span><span class="p">(</span><span class="n">Constants</span><span class="p">.</span><span class="na">HTTP_RETRY</span><span class="p">,</span> <span class="n">ruleHandle</span><span class="p">.</span><span class="na">getRetry</span><span class="p">());</span>
        <span class="k">return</span> <span class="n">chain</span><span class="p">.</span><span class="na">execute</span><span class="p">(</span><span class="n">exchange</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre>
     </div>
     <p>
      不知道是不是平时使用的是NGINX，所有感觉Soul网关的转发好像不是那么灵活
     </p>
     <p>
      比如我们配置： http://test/baidu ，转发到百度后端服务器： http://baidu.com
     </p>
     <p>
      如果我们按照两级来配置的话，那真实的url就会变成 http://baidu.com/baidu
     </p>
     <p>
      使用一级前缀配置能达到目的，都使用match，选择器配置一级前缀，规则配置 /** ，这样前缀为 test 的请求都会转到百度
     </p>
     <p>
      上面转发成功还是因为 规则： /** 能匹配 /test/ ，感觉没有NGINX类似的截取之类
     </p>
     <h2 id="_3">
      总结
     </h2>
     <p>
      通过分析Soul的匹配算法，对如果写配置有了更深的了解，下面两点是需要注意的：
     </p>
     <p>
      1.Soul网关只支持一级前缀，因为在设置RealURL的时候，分隔字符串后定时取取str[0]为前缀
     </p>
     <p>
      2.Soul网关选择器和规则的路径设置存在高度的关联性，前缀可以说必须进行继承
     </p>
     <p>
      了解了匹配的一些细节，有助于写匹配
     </p>
     <h2 id="soul_1">
      Soul网关源码分析文章列表
     </h2>
     <h3 id="github">
      Github
     </h3>
     <ul>
      <li>
       <a href="https://github.com/lw1243925457/SE-Notes/blob/master/profession/program/%E5%BC%80%E6%BA%90/soul/soul%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB1-%E6%A6%82%E8%A7%88.md">
        Soul源码阅读（一） 概览
       </a>
      </li>
      <li>
       <a href="https://github.com/lw1243925457/SE-Notes/blob/master/profession/program/%E5%BC%80%E6%BA%90/soul/soul%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB2-%E5%88%9D%E6%AD%A5%E8%BF%90%E8%A1%8C.md">
        Soul源码阅读（二）代码初步运行
       </a>
      </li>
      <li>
       <a href="https://github.com/lw1243925457/SE-Notes/blob/master/profession/program/%E5%BC%80%E6%BA%90/soul/soul%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB3-%E8%AF%B7%E6%B1%82%E5%A4%84%E7%90%86%E6%A6%82%E8%A7%88.md">
        Soul源码阅读（三）HTTP请求处理概览
       </a>
      </li>
      <li>
       <a href="https://github.com/lw1243925457/SE-Notes/blob/master/profession/program/%E5%BC%80%E6%BA%90/soul/soul%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB4-dubbo%E8%AF%B7%E6%B1%82%E6%A6%82%E8%A7%88.md">
        Soul网关源码阅读（四）Dubbo请求概览
       </a>
      </li>
      <li>
       <a href="https://github.com/lw1243925457/SE-Notes/blob/master/profession/program/%E5%BC%80%E6%BA%90/soul/soul%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB5-%E8%AF%B7%E6%B1%82%E7%B1%BB%E5%9E%8B%E6%8E%A2%E7%B4%A2.md">
        Soul网关源码阅读（五）请求类型探索
       </a>
      </li>
      <li>
       <a href="https://github.com/lw1243925457/SE-Notes/blob/master/profession/program/%E5%BC%80%E6%BA%90/soul/soul%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB6-sofa%E8%AF%B7%E6%B1%82%E5%A4%84%E7%90%86%E6%A6%82%E8%A7%88.md">
        Soul网关源码阅读（六）Sofa请求处理概览
       </a>
      </li>
      <li>
       <p>
        <a href="https://github.com/lw1243925457/SE-Notes/blob/master/profession/program/%E5%BC%80%E6%BA%90/soul/soul%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB7-%E9%99%90%E6%B5%81%E6%8F%92%E4%BB%B6%E5%88%9D%E6%8E%A2.md">
         Soul网关源码阅读（七）限流插件初探
        </a>
       </p>
      </li>
      <li>
       <p>
        <a href="https://github.com/lw1243925457/SE-Notes/blob/master/profession/program/%E5%BC%80%E6%BA%90/soul/soul%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB%E7%95%AA%E5%A4%96%E7%AF%871-HTTP%E7%A4%BA%E4%BE%8B%E5%8F%82%E6%95%B0%E8%AF%B7%E6%B1%82%E9%94%99%E8%AF%AF.md">
         Soul网关源码阅读番外篇（一） HTTP参数请求错误
        </a>
       </p>
      </li>
     </ul>
     <h3 id="_4">
      掘金
     </h3>
     <ul>
      <li>
       <a href="https://juejin.cn/post/6917864624423436296">
        Soul网关源码阅读（一） 概览
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6917865804121767944">
        Soul网关源码阅读（二）代码初步运行
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6917866538712334343">
        Soul网关源码阅读（三）请求处理概览
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6917867369909977102">
        Soul网关源码阅读（四）Dubbo请求概览
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6918575905962983438">
        Soul网关源码阅读（五）请求类型探索
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6918736260467015693">
        Soul网关源码阅读（六）Sofa请求处理概览
       </a>
      </li>
      <li>
       <p>
        <a href="https://juejin.cn/post/6919348164944232455/">
         Soul网关源码阅读（七）限流插件初探
        </a>
       </p>
      </li>
      <li>
       <p>
        <a href="https://juejin.cn/post/6918947689564471309">
         Soul网关源码阅读番外篇（一） HTTP参数请求错误
        </a>
       </p>
      </li>
     </ul>
    </article>
   </div>
   <!-- Footer -->
   <footer id="footer">
    <p class="copyright">
     © Untitled. Design:
     <a href="https://html5up.net">
      HTML5 UP
     </a>
     .
    </p>
   </footer>
  </div>
  <!-- BG -->
  <div id="bg">
  </div>
  <!-- Scripts -->
  <script src="../assets/js/jquery.min.js">
  </script>
  <script src="../assets/js/browser.min.js">
  </script>
  <script src="../assets/js/breakpoints.min.js">
  </script>
  <script src="../assets/js/util.js">
  </script>
  <script src="../assets/js/main.js">
  </script>
 </body>
</html>
